/*
作者：sth(在747929791基础上修改）
这是一个十分简单的AI的样例
*/

#include "sdk/sdk.h"
#include "sdk/misc.h"
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <algorithm>

using Pos = SDK::Pos;
using PPlayerInfo = SDK::PPlayerInfo;
using PCommand = SDK::PCommand;
using PShowInfo = SDK::PShowInfo;
using Edge = PPlayerInfo::Edge;
using Robot = PPlayerInfo::Robot;
using HumanOrder = PPlayerInfo::HumanOrder;
using Buff = Robot::Buff;
using Skill = Robot::Skill;
using Operation = PCommand::Operation;
using ShowInfo = PShowInfo::ShowInfo;

PPlayerInfo playerInfo;
PCommand pCommand;
PShowInfo *pShowInfo;

const double eps = 0.05;


//样例AI
class sthAI
{
private:
    //对局开始的初始化
    void init()
    {
        srand(time(NULL));
    }

    void sort(vector<Robot*>& robot)
    {
        for (int i = 0; i < robot.size(); ++i)
            for (int j = robot.size() - 1; j > i; --j)
                if (robot[j]->hp < robot[j - 1]->hp)
                {
                    Robot* tmp = robot[j];
                    robot[j] = robot[j - 1];
                    robot[j - 1] = tmp;
                }
    }

    void sort_pos_by_energy(vector<Pos>& pos)
    {
        for (int i = 0; i < pos.size(); ++i)
            for (int j = pos.size() - 1; j > i; --j)
                if (ENERGY[pos[j].x][pos[j].y] > ENERGY[pos[j - 1].x][pos[j - 1].y])
                {
                    Pos tmp = pos[j];
                    pos[j]  = pos[j - 1];
                    pos[j - 1] = tmp;
                }
    }

    bool canuse(Robot* robot, SkillType skill)//通过cd和energy判断一个技能是否可以使用
    {
        if (skill != SkillType::EvolveSkill)//目前(2017.3.8)skills列表里没有evolve（被特意隐藏
            for (int i = 0; i < robot->skills.size(); ++i)//不清楚skills列表里的技能是不是都是冷却好的
                if (robot->skills[i].type == skill)
                    if (robot->skills[i].cd != 0) return false;
                    else break;
        if (robot->energy >= robot->consumption + Robot::Skill::Cost(skill, robot->level, robot->type))
            return true;
        else
            return false;
    }

    Robot* chooseenemy(const vector<Robot*>& enemyRobot, const Pos& pos, int range) // 在敌人列表中选择一个机器人，使得它与给定位置的距离<range
    {
        for (int i = 0; i < enemyRobot.size(); ++i)
        {
            Robot* ene = enemyRobot[i];
            int dx = pos.x - ene->pos.x;
            int dy = pos.y - ene->pos.y;
            if(dx * dx + dy * dy <= range)
                return ene;
        }
        return NULL;
    }





public:

    //主过程，通过playerInfo得到pCommand
    void solve() {
        //思路：按照随机顺序对每个我方机器人发布可行的随机指令
        pCommand.cmds.clear();
        if (playerInfo.round == 0)
            init();

        vector<Robot *> MyRobot, EnemyRobot;//我方机器人列表，敌方机器人列表
        vector<Pos> BuildAblePos;//当前地图上的空地
        //构造MyRobot, EnemyRobot
        for (unsigned int i = 0; i < playerInfo.robots.size(); i++) {
            Robot &obj = playerInfo.robots[i];
            if (obj.team == playerInfo.team)
                MyRobot.push_back(&obj);
            else
                EnemyRobot.push_back(&obj);
        }

        for (int x = 0; x < MAP_SIZE; x++)
            for (int y = 0; y < MAP_SIZE; y++)
                if (MAP[x][y] == 1 && playerInfo.RobotAt(Pos(x, y)) == NULL)
                    BuildAblePos.push_back(Pos(x, y));

        //敌方机器人按照其剩余血量升序排列
        sort(EnemyRobot);

        //将空地按照ENERGY降序排列，并将ENERGY相同的相对顺序打乱（以此来让split相对分散）
        sort_pos_by_energy(BuildAblePos);

        {
            int i = 0;
            while (i < BuildAblePos.size())
            {
                double e = ENERGY[BuildAblePos[i].x][BuildAblePos[i].y];
                int j;
                for (j = i;j < BuildAblePos.size() && e - eps < ENERGY[BuildAblePos[j].x][BuildAblePos[j].y]; ++j);
                random_shuffle(BuildAblePos.begin() + i, BuildAblePos.begin() + j);
                i = j;
            }

        }


        //将数组随机打乱
        //random_shuffle(MyRobot.begin(), MyRobot.end());
        //random_shuffle(EnemyRobot.begin(), EnemyRobot.end());
        //random_shuffle(BuildAblePos.begin(), BuildAblePos.end());
        if (playerInfo.round == 0)
        {

            for (int i = 0; i < BuildAblePos.size(); ++i)
                printf("%.1f (%d , %d)\n", ENERGY[BuildAblePos[i].x][BuildAblePos[i].y],BuildAblePos[i].x, BuildAblePos[i].y);
        }
        //随机甩技能
        printf("myrobot_num = %d  enemyrobot_num = %d  blank_num = %d\n", MyRobot.size(), EnemyRobot.size(), BuildAblePos.size());
        for (unsigned int id = 0; id < MyRobot.size(); id++)
        {
            Robot* robot = MyRobot[id];

            //printf("robot type = %s  level = %d\n", RobotTypeString[robot->type], robot->level);
            if (robot->level == 0)
                if (MyRobot.size()!= 1 && rand()&1 && canuse(robot, EvolveSkill))
                {
                    pCommand.AddOrder(OrderType::Evolve, robot->pos ,(RobotType) (rand() % 3 + 1));
                    printf("use evolve\n");
                    continue;
                }
                else if(canuse(robot, SplitSkill) && BuildAblePos.size())
                {
                    bool useskill = false;
                    for (int i = 0; i < BuildAblePos.size(); ++ i)
                    {
                        int dx = robot->pos.x - BuildAblePos[i].x;
                        int dy = robot->pos.y - BuildAblePos[i].y;
                        if (dx * dx + dy * dy <= SplitRange)
                        {
                            pCommand.AddOrder(Split, robot->pos, BuildAblePos[i]);
                            BuildAblePos.erase(BuildAblePos.begin() + i);
                            useskill = true;
                            printf("use split  ENERGY= %.1f\n", ENERGY[BuildAblePos[i].x][BuildAblePos[i].y]);
                            break;
                        }
                    }
                    if (useskill)
                    {
                        continue;
                    }
                }
                else
                {
                    Robot* enemy = chooseenemy(EnemyRobot, robot->pos, robot->attack_range);
                    if (enemy == NULL) continue;
                    pCommand.AddOrder(PlainAttack, robot->pos, enemy->pos);
                    printf("use plainattack\n");
                    continue;
                }

            if (robot->level == 0) continue;


            //任何类型的机器人都可以split和evolve
            int tmp_robotnum = MyRobot.size();
            if (tmp_robotnum < EnemyRobot.size() || canuse(robot, SkillType::SplitSkill) && rand()%10 == 0)
            {
                tmp_robotnum++;
                bool useskill = false;
                for (int i = 0; i < BuildAblePos.size(); ++ i)
                {
                    int dx = robot->pos.x - BuildAblePos[i].x;
                    int dy = robot->pos.y - BuildAblePos[i].y;
                    if (dx * dx + dy * dy <= SplitRange)
                    {
                        pCommand.AddOrder(Split, robot->pos, BuildAblePos[i]);
                        BuildAblePos.erase(BuildAblePos.begin() + i);
                        useskill = true;
                        printf("use split  ENERGY= %.1f\n", ENERGY[BuildAblePos[i].x][BuildAblePos[i].y]);
                        break;
                    }
                }
                if (useskill)
                {
                    continue;
                }
            }

            //数目少的时候升级太不划算，暂时不考虑1级后继续升级
            /*
            if (canuse(robot, SkillType::EvolveSkill) && rand()%10 <= 1)
            {
                pCommand.AddOrder(OrderType::Evolve, robot->pos ,(RobotType) robot->type);
                printf("use evolve\n");
                continue;
            }
             */


            //不同类型的robot释放各自类型的skill

            bool useskill = false;
            switch (robot->type)
            {
                case RobotType::AttackRobot :
                    if (rand() & 1)//使用scourge技能
                    {
                        if (canuse(robot, SkillType::ScourgeSkill))
                        {
                            Robot *enemy = chooseenemy(EnemyRobot, robot->pos, robot->attack_range);
                            if (enemy == NULL) break;
                            pCommand.AddOrder(OrderType::Scourge, robot->pos, enemy->pos);
                            printf("use Scourge\n");
                            useskill = true;
                        }
                    }
                    else if (canuse(robot, SkillType::BombingSkill))
                    {
                        Robot *enemy = chooseenemy(EnemyRobot, robot->pos, robot->attack_range);
                        if (enemy == NULL) break;
                        pCommand.AddOrder(OrderType::Bombing, robot->pos, enemy->pos);
                        printf("use Bombing\n");
                        useskill = true;
                    }
                    break;
                case RobotType::GatherRobot:
                    /*
                    for (int i = 0; i < robot->skills.size(); ++i)
                        if (robot->skills[i].type == SkillType::OverloadSkill)
                            printf("overload cd = %d\n", robot->skills[i].cd);
                     */
                    if (rand() & 1 && canuse(robot, SkillType::OverloadSkill))
                    {
                        pCommand.AddOrder(OrderType::Overload, robot->pos);
                        useskill = true;
                    }
                    break;
                case RobotType ::DefenseRobot:
                    if (rand() & 1)
                    {
                        if (canuse(robot, SkillType::RecoverSkill))
                        {
                            pCommand.AddOrder(OrderType::Recover, robot->pos, robot->pos);
                            useskill = true;
                        }
                    }
                    else
                        if (canuse(robot, SkillType::ShieldingSkill))
                        {
                            pCommand.AddOrder(OrderType::Shielding, robot->pos, robot->pos);
                            useskill = true;
                        }
                    break;
                default:
                    break;
            }
            if (useskill) continue;

            Robot* enemy = chooseenemy(EnemyRobot, robot->pos, robot->attack_range);
            if (enemy == NULL) continue;
            pCommand.AddOrder(PlainAttack, robot->pos, enemy->pos);
            printf("use plainattack\n");


        }
    }

}sthai;


//普通AI接口，一回合调用一次
extern "C"
{
__declspec(dllexport) void player_ai(const PlayerInfo &playerInfo_, Commands &pCommand_, PShowInfo &pShowInfo_)
{
    playerInfo = SDK::interpretPlayerInfo(playerInfo_);
    sthai.solve();
    pCommand_ = SDK::translateCommands(playerInfo, pCommand);
    return;
}
}

